package com.yvan.dsf;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.registry.Registry;
import com.alibaba.dubbo.registry.RegistryFactory;
import com.yvan.dsf.anno.DsfService;
import com.yvan.dsf.listener.ProtocolDict;
import com.yvan.platform.StringUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.Map;

@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@ConditionalOnBean(annotation = EnableDsfConfiguration.class)
@AutoConfigureAfter(DsfAutoConfiguration.class)
@EnableConfigurationProperties(DsfProperties.class)
public class DsfProviderAutoConfiguration implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Autowired
    private ApplicationConfig applicationConfig;
    @Autowired
    private ProtocolDict protocolConfig;
    @Autowired
    private RegistryConfig registryConfig;
    @Autowired
    private DsfProperties properties;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void init() throws Exception {
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(DsfService.class);
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            publishDubboService(entry.getKey(), entry.getValue());
        }
    }

    public void publishDubboService(String beanName, Object bean) throws Exception {
        //Service service = applicationContext.findAnnotationOnBean(beanName, Service.class);
        Service service = null;
        if (AopUtils.isAopProxy(bean)) {
            service = AnnotatedElementUtils.findMergedAnnotation(
                    AopUtils.getTargetClass(bean),
                    Service.class);
        } else {
            service = AnnotatedElementUtils.findMergedAnnotation(bean.getClass(), Service.class);
        }

        ServiceBean<Object> serviceConfig = new ServiceBean<>(service);
        if (void.class.equals(service.interfaceClass())
                && "".equals(service.interfaceName())) {
            if (bean.getClass().getInterfaces().length > 0) {
                serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
            } else {
                throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
            }
        }
        serviceConfig.setApplicationContext(applicationContext);
        serviceConfig.setApplication(applicationConfig);
        serviceConfig.setProtocol(protocolConfig.getDubboProtocol());
        serviceConfig.setRegistry(registryConfig);
        serviceConfig.afterPropertiesSet();
        serviceConfig.setRef(bean);
        if(StringUtils.isNotBlank(applicationConfig.getOwner())){
            serviceConfig.setOwner(applicationConfig.getOwner());
        }
        if(StringUtils.isNotBlank(properties.getDebugger())){
            Map<String,String> extParameters= new LinkedHashMap<>();
            extParameters.put("debugger",properties.getDebugger());
            serviceConfig.setParameters(extParameters);
        }
        serviceConfig.export();

        RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class)
                .getAdaptiveExtension();
        Registry registry = registryFactory.getRegistry(URL.valueOf(registryConfig.getAddress()));
        for(URL url :serviceConfig.getExportedUrls()){
            registry.register(URL.valueOf(String.format("routers://0.0.0.0/%s?name=debugger_param&category=routers&router=param&dynamic=true",url.getServiceInterface())));
        }
    }
}
